﻿/*
* Copyright (c) 2010-2011 Tesla Engine Group
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

using System;
using Microsoft.Xna.Framework.Content.Pipeline;
using Tesla.Content;
using Tesla.Core;
using Tesla.Graphics;
using Tesla.Xna.Content.Loaders;
using Tesla.Xna.Graphics;

namespace TeslaEffectCompiler {
    /// <summary>
    /// XNA 4.0 effect compiler. Works for both Xbox360 and Windows (requires XNA 4.0 GameStudio
    /// to be installed).
    /// </summary>
    public sealed class XNAEffectCompiler : IEffectCompiler {
        private TargetPlatform _target;
        private XNAEffectLoader _loader;
        private bool _isDisposed;
        private ContentManager _content;

        /// <summary>
        /// Gets or sets the target.
        /// </summary>
        /// <value>
        /// The target.
        /// </value>
        public TargetPlatform Target {
            get {
                return _target;
            }
            set {
                _target = value;
                if(_loader != null) {
                    _loader.XNAContext = new TeslaProcessorContext(_target);
                }
            }
        }

        /// <summary>
        /// Gets if the compiler's resources has been disposed.
        /// </summary>
        public bool IsDisposed {
            get {
                return _isDisposed;
            }
        }

        /// <summary>
        /// Creates a new instance of <see cref="XNAEffectCompiler"/>.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        public XNAEffectCompiler(String filePath) {
            _isDisposed = false;
            _target = TargetPlatform.Windows;
            _content = new ContentManager(new FileResourceLocator(filePath));
            _loader = new XNAEffectLoader();
            _content.RegisterLoader(_loader);
        }

        /// <summary>
        /// Creates a new instance of <see cref="XNAEffectCompiler"/>.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        /// <param name="platform">The platform.</param>
        public XNAEffectCompiler(String filePath, TargetPlatform platform) {
            _isDisposed = false;
            _target = platform;
            _content = new ContentManager(new FileResourceLocator(filePath));
            _loader = new XNAEffectLoader();
            _content.RegisterLoader(_loader);
        }

        /// <summary>
        /// Releases unmanaged resources and performs other cleanup operations before the
        /// <see cref="XNAEffectCompiler"/> is reclaimed by garbage collection.
        /// </summary>
        ~XNAEffectCompiler() {
            Dispose(false);
        }

        /// <summary>
        /// Initialize the compiler's resources.
        /// </summary>
        public void Init() {
            Engine.Initialize(new XNARenderSystemProvider());
        }

        /// <summary>
        /// Compiles a list of files
        /// </summary>
        /// <param name="files"></param>
        /// <param name="progress"></param>
        /// <returns></returns>
        public Effect[] Compile(String[] files, CompileProgress progress) {
            Effect[] effects = new Effect[files.Length];

            for(int i = 0; i < files.Length; i++) {
                if(progress != null) {
                    progress();
                }
                effects[i] = _content.Load<Effect>(files[i]);
            }
            return effects;
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing) {
            if(!_isDisposed) {
                if(disposing) {
                    _content.Dispose();
                    Engine.CleanUpResources();
                }
                _isDisposed = true;
            }
        }

    }
}
